home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cdrtools-1.10 / misc / readcd.c < prev   
Encoding:
C/C++ Source or Header  |  2000-07-30  |  26.4 KB  |  1,144 lines

  1. /* @(#)readcd.c    1.21 00/07/30 Copyright 1987 J. Schilling */
  2. #ifndef lint
  3. static    char sccsid[] =
  4.     "@(#)readcd.c    1.21 00/07/30 Copyright 1987 J. Schilling";
  5. #endif
  6. /*
  7.  *    Skeleton for the use of the scg genearal SCSI - driver
  8.  *
  9.  *    Copyright (c) 1987 J. Schilling
  10.  */
  11. /*
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2, or (at your option)
  15.  * any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; see the file COPYING.  If not, write to
  24.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  */
  26.  
  27. #include <mconfig.h>
  28. #include <stdio.h>
  29. #include <standard.h>
  30. #include <unixstd.h>
  31. #include <stdxlib.h>
  32. #include <strdefs.h>
  33. #include <fctldefs.h>
  34. #include <timedefs.h>
  35. #include <schily.h>
  36.  
  37. #include <scg/scgcmd.h>
  38. #include <scg/scsireg.h>
  39. #include <scg/scsitransp.h>
  40.  
  41. #include "cdrecord.h"
  42.  
  43. char    cdr_version[] = "1.10a02";
  44.  
  45. #if     defined(PROTOTYPES)
  46. #define UINT_C(a)    (a##u)
  47. #define ULONG_C(a)    (a##ul)
  48. #define USHORT_C(a)    (a##uh)
  49. #define CONCAT(a,b)    a##b
  50. #else
  51. #define UINT_C(a)    ((unsigned)(a))
  52. #define ULONG_C(a)    ((unsigned long)(a))
  53. #define USHORT_C(a)    ((unsigned short)(a))
  54. #define CONCAT(a,b)    a/**/b
  55. #endif
  56.  
  57. extern    BOOL    getlong        __PR((char *, long *, long, long));
  58. extern    BOOL    getint        __PR((char *, int *, int, int));
  59.  
  60. typedef struct {
  61.     long    start;
  62.     long    end;
  63.     long    sptr;        /* sectors per transfer */
  64.     BOOL    askrange;
  65.     char    *name;
  66. } parm_t;
  67.  
  68. typedef struct {
  69.     int    errors;
  70.     int    c2_errors;
  71.     int    c2_errsecs;
  72.     int    secsize;
  73.     BOOL    ismmc;
  74. } rparm_t;
  75.  
  76. EXPORT    BOOL    cvt_cyls    __PR((void));
  77. EXPORT    BOOL    cvt_bcyls    __PR((void));
  78. EXPORT    void    print_defect_list __PR((void));
  79. LOCAL    void    usage        __PR((int ret));
  80. EXPORT    int    main        __PR((int ac, char **av));
  81. LOCAL    int    prstats        __PR((void));
  82. LOCAL    void    dorw        __PR((SCSI *scgp, char *filename, char* sectors));
  83. LOCAL    void    doit        __PR((SCSI *scgp));
  84. LOCAL    void    read_disk    __PR((SCSI *scgp, parm_t *parmp));
  85. LOCAL    void    readc2_disk    __PR((SCSI *scgp, parm_t *parmp));
  86.  
  87. LOCAL    int    fread_data    __PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
  88. LOCAL    int    bits        __PR((int c));
  89. LOCAL    int    bitidx        __PR((int c));
  90. LOCAL    int    fread_c2    __PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
  91.  
  92. LOCAL    int    fdata_null    __PR((rparm_t *rp, caddr_t bp, long addr, int cnt));
  93. LOCAL    int    fdata_c2    __PR((rparm_t *rp, caddr_t bp, long addr, int cnt));
  94.  
  95. #ifdef    used
  96. LOCAL    int read_scsi_g1    __PR((SCSI *scgp, caddr_t bp, long addr, int cnt));
  97. #endif
  98.  
  99. EXPORT    int    write_scsi    __PR((SCSI *scgp, caddr_t bp, long addr, int cnt));
  100. EXPORT    int    write_g0    __PR((SCSI *scgp, caddr_t bp, long addr, int cnt));
  101. EXPORT    int    write_g1    __PR((SCSI *scgp, caddr_t bp, long addr, int cnt));
  102.  
  103. #ifdef    used
  104. LOCAL    void    Xrequest_sense    __PR((SCSI *scgp));
  105. #endif
  106. LOCAL    int    read_retry    __PR((SCSI *scgp, caddr_t bp, long addr, long cnt,
  107.                     int (*rfunc)(SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt),
  108.                     rparm_t *rp
  109.                     ));
  110. LOCAL    void    read_generic    __PR((SCSI *scgp, parm_t *parmp,
  111.                     int (*rfunc)(SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt),
  112.                     rparm_t *rp,
  113.                     int (*dfunc)(rparm_t *rp, caddr_t bp, long addr, int cnt)
  114. ));
  115. LOCAL    void    write_disk    __PR((SCSI *scgp, parm_t *parmp));
  116. LOCAL    int    choice        __PR((int n));
  117. LOCAL    void    ra        __PR((SCSI *scgp));
  118.  
  119. EXPORT    int    read_da        __PR((SCSI *scgp, caddr_t bp, long addr, int cnt, int framesize, int subcode));
  120. EXPORT    int    read_cd        __PR((SCSI *scgp, caddr_t bp, long addr, int cnt, int framesize, int data, int subch));
  121.  
  122.  
  123. struct timeval    starttime;
  124. struct timeval    stoptime;
  125.  
  126. char    *Sbuf;
  127. long    Sbufsize;
  128.  
  129. /*#define    MAX_RETRY    32*/
  130. #define    MAX_RETRY    128
  131.  
  132. int    help;
  133. BOOL    is_suid;
  134. BOOL    is_cdrom;
  135. BOOL    do_write;
  136. BOOL    c2scan;
  137. BOOL    fulltoc;
  138. BOOL    noerror;
  139. int    retries = MAX_RETRY;
  140.  
  141. struct    scsi_format_data fmt;
  142.  
  143. /*XXX*/EXPORT    BOOL cvt_cyls(){ return (FALSE);}
  144. /*XXX*/EXPORT    BOOL cvt_bcyls(){ return (FALSE);}
  145. /*XXX*/EXPORT    void print_defect_list(){}
  146.  
  147. LOCAL void
  148. usage(ret)
  149.     int    ret;
  150. {
  151.     error("Usage:\treadcd [options]\n");
  152.     error("options:\n");
  153.     error("\t-version    print version information and exit\n");
  154.     error("\tdev=target    SCSI target to use\n");
  155.     error("\tf=filename    Name of file to read/write\n");
  156.     error("\tsectors=range    Range of sectors to read/write\n");
  157.     error("\t-w        Switch to write mode\n");
  158.     error("\t-c2scan        Do a C2 error scan\n");
  159.     error("\tkdebug=#,kd=#\tdo Kernel debugging\n");
  160.     error("\t-v        increment general verbose level by one\n");
  161.     error("\t-V        increment SCSI command transport verbose level by one\n");
  162.     error("\t-silent,-s\tdo not print status of erreneous commands\n");
  163.     error("\t-noerror    do not abort on error\n");
  164.     error("\tretries=#    set retry count (default is %d)\n", retries);
  165.     exit(ret);
  166. }    
  167.  
  168. char    opts[]   = "kdebug#,kd#,verbose+,v+,Verbose,V+,silent,s,debug,help,h,version,dev*,sectors*,w,c2scan,fulltoc,noerror,retries#,f*";
  169.  
  170. EXPORT int
  171. main(ac, av)
  172.     int    ac;
  173.     char    *av[];
  174. {
  175.     char    *dev = NULL;
  176.     int    fcount;
  177.     int    cac;
  178.     char    * const *cav;
  179.     int    scsibus    = 0;
  180.     int    target    = 0;
  181.     int    lun    = 0;
  182.     int    silent    = 0;
  183.     int    verbose    = 0;
  184.     int    lverbose= 0;
  185.     int    kdebug    = 0;
  186.     int    debug    = 0;
  187.     int    pversion = 0;
  188.     SCSI    *scgp;
  189.     char    *filename= NULL;
  190.     char    *sectors = NULL;
  191.  
  192.     save_args(ac, av);
  193.  
  194.     cac = --ac;
  195.     cav = ++av;
  196.  
  197.     if(getallargs(&cac, &cav, opts,
  198.             &kdebug, &kdebug,
  199.             &verbose, &verbose,
  200.             &lverbose, &lverbose,
  201.             &silent, &silent, &debug,
  202.             &help, &help, &pversion,
  203.             &dev, §ors, &do_write,
  204.             &c2scan, &fulltoc,
  205.             &noerror, &retries, &filename) < 0) {
  206.         errmsgno(EX_BAD, "Bad flag: %s.\n", cav[0]);
  207.         usage(EX_BAD);
  208.     }
  209.     if (help)
  210.         usage(0);
  211.     if (pversion) {
  212.         printf("readcd %s (%s-%s-%s) Copyright (C) 1987, 1995-2000 J÷rg Schilling\n",
  213.                                 cdr_version,
  214.                                 HOST_CPU, HOST_VENDOR, HOST_OS);
  215.         exit(0);
  216.     }
  217.  
  218.     fcount = 0;
  219.     cac = ac;
  220.     cav = av;
  221.  
  222.     while(getfiles(&cac, &cav, opts) > 0) {
  223.         fcount++;
  224.         if (fcount == 1) {
  225.             if (*astoi(cav[0], &target) != '\0') {
  226.                 errmsgno(EX_BAD,
  227.                     "Target '%s' is not a Number.\n",
  228.                                 cav[0]);
  229.                 usage(EX_BAD);
  230.                 /* NOTREACHED */
  231.             }
  232.         }
  233.         if (fcount == 2) {
  234.             if (*astoi(cav[0], &lun) != '\0') {
  235.                 errmsgno(EX_BAD,
  236.                     "Lun is '%s' not a Number.\n",
  237.                                 cav[0]);
  238.                 usage(EX_BAD);
  239.                 /* NOTREACHED */
  240.             }
  241.         }
  242.         if (fcount == 3) {
  243.             if (*astoi(cav[0], &scsibus) != '\0') {
  244.                 errmsgno(EX_BAD,
  245.                     "Scsibus is '%s' not a Number.\n",
  246.                                 cav[0]);
  247.                 usage(EX_BAD);
  248.                 /* NOTREACHED */
  249.             }
  250.         } else {
  251.             scsibus = 0;
  252.         }
  253.         cac--;
  254.         cav++;
  255.     }
  256. /*error("dev: '%s'\n", dev);*/
  257.  
  258.     if (dev) {
  259.         char    errstr[80];
  260.  
  261.         if ((scgp = scg_open(dev, errstr, sizeof(errstr), debug, lverbose)) == (SCSI *)0)
  262.             comerr("%s%sCannot open SCSI driver.\n", errstr, errstr[0]?". ":"");
  263.     } else {
  264.         if (scsibus == -1 && target >= 0 && lun >= 0)
  265.             scsibus = 0;
  266.  
  267.         scgp = scg_smalloc();
  268.         scgp->debug = debug;
  269.         scgp->kdebug = kdebug;
  270.         scgp->scsibus = scsibus;
  271.         scgp->target = target;
  272.         scgp->lun = lun;
  273.  
  274.         if (!scg__open(scgp, NULL, scsibus, target, lun))
  275.             comerr("Cannot open SCSI driver.\n");
  276.  
  277.         scgp->scsibus = scsibus;
  278.         scgp->target = target;
  279.         scgp->lun = lun;
  280.     }
  281.     scgp->silent = silent;
  282.     scgp->verbose = verbose;
  283.     scgp->debug = debug;
  284.     scgp->kdebug = kdebug;
  285. /*    scg_settimeout(scgp, timeout);*/
  286.     scg_settimeout(scgp, 40);
  287.  
  288.     Sbufsize = scg_bufsize(scgp, 256*1024L);
  289.     if ((Sbuf = scg_getbuf(scgp, Sbufsize)) == NULL)
  290.         comerr("Cannot get SCSI I/O buffer.\n");
  291.  
  292.     is_suid = geteuid() != getuid();
  293.     /*
  294.      * We don't need root privilleges anymore.
  295.      */
  296. #ifdef    HAVE_SETREUID
  297.     if (setreuid(-1, getuid()) < 0)
  298. #else
  299. #ifdef    HAVE_SETEUID
  300.     if (seteuid(getuid()) < 0)
  301. #else
  302.     if (setuid(getuid()) < 0)
  303. #endif
  304. #endif
  305.         comerr("Panic cannot set back efective uid.\n");
  306.  
  307.     /* code to use SCG */
  308.  
  309.     do_inquiry(scgp, FALSE);
  310.     if (is_suid) {
  311.         if (scgp->inq->type != INQ_ROMD)
  312.             comerrno(EX_BAD, "Not root. Will only work on CD-ROM in suid mode\n");
  313.     }
  314.  
  315.     if (filename || sectors || c2scan || fulltoc) {
  316.         dorw(scgp, filename, sectors);
  317.     } else {
  318.         doit(scgp);
  319.     }
  320.     return (0);
  321. }
  322.  
  323. /*
  324.  * Return milliseconds since start time.
  325.  */
  326. LOCAL int
  327. prstats()
  328. {
  329.     int    sec;
  330.     int    usec;
  331.     int    tmsec;
  332.  
  333.     if (gettimeofday(&stoptime, (struct timezone *)0) < 0)
  334.         comerr("Cannot get time\n");
  335.  
  336.     sec = stoptime.tv_sec - starttime.tv_sec;
  337.     usec = stoptime.tv_usec - starttime.tv_usec;
  338.     tmsec = sec*1000 + usec/1000;
  339. #ifdef    lint
  340.     tmsec = tmsec;    /* Bisz spaeter */
  341. #endif
  342.     if (usec < 0) {
  343.         sec--;
  344.         usec += 1000000;
  345.     }
  346.  
  347.     error("Time total: %d.%03dsec\n", sec, usec/1000);
  348.     return (1000*sec + (usec / 1000));
  349. }
  350.  
  351. LOCAL void
  352. dorw(scgp, filename, sectors)
  353.     SCSI    *scgp;
  354.     char    *filename;
  355.     char    *sectors;
  356. {
  357.     parm_t    params;
  358.     char    *p = NULL;
  359.  
  360.     params.start = 0;
  361.     params.end = -1;
  362.     params.sptr = -1;
  363.     params.askrange = FALSE;
  364.     params.name = NULL;
  365.  
  366.     if (filename)
  367.         params.name = filename;
  368.     if (sectors)
  369.         p = astol(sectors, ¶ms.start);
  370.     if (p && *p == '-')
  371.         p = astol(++p, ¶ms.end);
  372.     if (p && *p != '\0')
  373.         comerrno(EX_BAD, "Not a valid sector range '%s'\n", sectors);
  374.  
  375.     if (!wait_unit_ready(scgp, 60))
  376.         comerr("Device not ready.\n");
  377.  
  378.     if (c2scan) {
  379.         if (params.name == NULL)
  380.             params.name = "/dev/null";
  381.         readc2_disk(scgp, ¶ms);
  382.     } else if (do_write)
  383.         write_disk(scgp, ¶ms);
  384.     else
  385.         read_disk(scgp, ¶ms);
  386. }
  387.  
  388. LOCAL void
  389. doit(scgp)
  390.     SCSI    *scgp;
  391. {
  392.     int    i = 0;
  393.     parm_t    params;
  394.  
  395.     params.start = 0;
  396.     params.end = -1;
  397.     params.sptr = -1;
  398.     params.askrange = TRUE;
  399.     params.name = "/dev/null";
  400.  
  401.     for(;;) {
  402.         if (!wait_unit_ready(scgp, 60))
  403.             comerr("Device not ready.\n");
  404.  
  405.         printf("0:read 1:veri   2:erase   3:read buffer 4:cache 5:ovtime 6:cap\n");
  406.         printf("7:wne  8:floppy 9:verify 10:checkcmds  11:read disk 12:write disk\n");
  407.         printf("13:scsireset 14:seektest 15: readda 16: reada 17: c2err\n");
  408.  
  409.         getint("Enter selection:", &i, 0, 20);
  410.         switch (i) {
  411.  
  412.         case 11:    read_disk(scgp, 0);    break;
  413.         case 12:    write_disk(scgp, 0);    break;
  414.         case 15:    ra(scgp);        break;
  415. /*        case 16:    reada_disk(scgp, 0, 0);    break;*/
  416.         case 17:    readc2_disk(scgp, ¶ms);    break;
  417.         }
  418.     }
  419. }
  420.  
  421. LOCAL void
  422. read_disk(scgp, parmp)
  423.     SCSI    *scgp;
  424.     parm_t    *parmp;
  425. {
  426.     rparm_t    rp;
  427.  
  428.     read_capacity(scgp);
  429.     rp.errors = 0;
  430.     rp.c2_errors = 0;
  431.     rp.c2_errsecs = 0;
  432.     rp.secsize = scgp->cap->c_bsize;
  433.  
  434.     read_generic(scgp, parmp, fread_data, &rp, fdata_null);
  435. }
  436.  
  437.  
  438. char    zeroblk[512];
  439.  
  440. LOCAL void
  441. readc2_disk(scgp, parmp)
  442.     SCSI    *scgp;
  443.     parm_t    *parmp;
  444. {
  445.     rparm_t    rp;
  446.  
  447.     rp.errors = 0;
  448.     rp.c2_errors = 0;
  449.     rp.c2_errsecs = 0;
  450.     rp.secsize = 2352 + 294;
  451.     rp.ismmc = is_mmc(scgp, NULL);
  452.  
  453.  
  454.     read_generic(scgp, parmp, fread_c2, &rp, fdata_c2);
  455.  
  456.     printf("C2 errors total: %d bytes in %d sectors on disk\n", rp.c2_errors, rp.c2_errsecs);
  457.     printf("C2 errors rate: %f%% \n", (100.0*rp.c2_errors)/scgp->cap->c_baddr/2352);
  458. }
  459.  
  460. LOCAL int
  461. fread_data(scgp, rp, bp, addr, cnt)
  462.     SCSI    *scgp;
  463.     rparm_t    *rp;
  464.     caddr_t    bp;
  465.     long    addr;
  466.     int    cnt;
  467. {
  468.     return (read_g1(scgp, bp, addr, cnt));
  469. }
  470.  
  471.  
  472. int bits(c)
  473.     int    c;
  474. {
  475.     int    n = 0;
  476.  
  477.     if (c & 0x01)
  478.         n++;
  479.     if (c & 0x02)
  480.         n++;
  481.     if (c & 0x04)
  482.         n++;
  483.     if (c & 0x08)
  484.         n++;
  485.     if (c & 0x10)
  486.         n++;
  487.     if (c & 0x20)
  488.         n++;
  489.     if (c & 0x40)
  490.         n++;
  491.     if (c & 0x80)
  492.         n++;
  493.     return (n);
  494. }
  495.  
  496. int bitidx(c)
  497.     int    c;
  498. {
  499.     if (c & 0x80)
  500.         return (0);
  501.     if (c & 0x40)
  502.         return (1);
  503.     if (c & 0x20)
  504.         return (2);
  505.     if (c & 0x10)
  506.         return (3);
  507.     if (c & 0x08)
  508.         return (4);
  509.     if (c & 0x04)
  510.         return (5);
  511.     if (c & 0x02)
  512.         return (6);
  513.     if (c & 0x01)
  514.         return (7);
  515.     return (-1);
  516. }
  517.  
  518. LOCAL int
  519. fread_c2(scgp, rp, bp, addr, cnt)
  520.     SCSI    *scgp;
  521.     rparm_t    *rp;
  522.     caddr_t    bp;
  523.     long    addr;
  524.     int    cnt;
  525. {
  526.     if (rp->ismmc) {
  527.         return (read_cd(scgp, bp, addr, cnt, rp->secsize,
  528.             /* Sync + all headers + user data + EDC/ECC + C2 */
  529. /*            (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3 | 2 << 1),*/
  530.             (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3 | 1 << 1),
  531.                 /* without subchannels */
  532.             0));
  533.     } else {
  534.         return (read_da(scgp, bp, addr, cnt, rp->secsize,
  535.             /* Sync + all headers + user data + EDC/ECC + C2 */
  536.             0x04));
  537.     }
  538. }
  539.  
  540. LOCAL int
  541. fdata_null(rp, bp, addr, cnt)
  542.     rparm_t    *rp;
  543.     caddr_t    bp;
  544.     long    addr;
  545.     int    cnt;
  546. {
  547.     return (0);
  548. }
  549.  
  550. LOCAL int
  551. fdata_c2(rp, bp, addr, cnt)
  552.     rparm_t    *rp;
  553.     caddr_t    bp;
  554.     long    addr;
  555.     int    cnt;
  556. {
  557.     int    i;
  558.     int    j;
  559.     int    k;
  560.     char    *p;
  561.  
  562.     p = &bp[2352];
  563.  
  564.     for (i=0; i < cnt; i++, p += (2352+294)) {
  565. /*        scg_prbytes("XXX ", p, 294);*/
  566.         if ((j = cmpbytes(p, zeroblk, 294)) < 294) {
  567.             printf("C2 in sector: %3ld first at byte: %4d (0x%02X)", addr+i,
  568.                 j*8 + bitidx(p[j]), p[j]&0xFF);
  569.             for (j=0,k=0; j < 294; j++)
  570.                 k += bits(p[j]);
  571.             printf(" total: %4d errors\n", k);
  572. /*            scg_prbytes("XXX ", p, 294);*/
  573.             rp->c2_errors += k;
  574.             rp->c2_errsecs++;
  575.         }
  576.     }    
  577.     return (0);
  578. }
  579.  
  580. #ifdef    used
  581. LOCAL int
  582. read_scsi_g1(scgp, bp, addr, cnt)
  583.     SCSI    *scgp;
  584.     caddr_t    bp;
  585.     long    addr;
  586.     int    cnt;
  587. {
  588.     register struct    scg_cmd    *scmd = scgp->scmd;
  589.  
  590.     fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
  591.     scmd->addr = bp;
  592. /*    scmd->size = cnt*512;*/
  593.     scmd->size = cnt*scgp->cap->c_bsize;
  594.     scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
  595.     scmd->cdb_len = SC_G1_CDBLEN;
  596.     scmd->sense_len = CCS_SENSE_LEN;
  597.     scmd->target = scgp->target;
  598.     scmd->cdb.g1_cdb.cmd = 0x28;
  599.     scmd->cdb.g1_cdb.lun = scgp->lun;
  600.     g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
  601.     g1_cdblen(&scmd->cdb.g1_cdb, cnt);
  602.     
  603.     scgp->cmdname = "read extended";
  604.  
  605.     return (scg_cmd(scgp));
  606. }
  607. #endif
  608.  
  609. #define    G0_MAXADDR    0x1FFFFFL
  610.  
  611. EXPORT int
  612. write_scsi(scgp, bp, addr, cnt)
  613.     SCSI    *scgp;
  614.     caddr_t    bp;
  615.     long    addr;
  616.     int    cnt;
  617. {
  618.     if(addr <= G0_MAXADDR)
  619.         return(write_g0(scgp, bp, addr, cnt));
  620.     else
  621.         return(write_g1(scgp, bp, addr, cnt));
  622. }
  623.  
  624. EXPORT int
  625. write_g0(scgp, bp, addr, cnt)
  626.     SCSI    *scgp;
  627.     caddr_t    bp;
  628.     long    addr;
  629.     int    cnt;
  630. {
  631.     register struct    scg_cmd    *scmd = scgp->scmd;
  632.  
  633.     if (scgp->cap->c_bsize <= 0)
  634.         raisecond("capacity_not_set", 0L);
  635.  
  636.     fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
  637.     scmd->addr = bp;
  638.     scmd->size = cnt*scgp->cap->c_bsize;
  639.     scmd->flags = SCG_DISRE_ENA;
  640.     scmd->cdb_len = SC_G0_CDBLEN;
  641.     scmd->sense_len = CCS_SENSE_LEN;
  642.     scmd->target = scgp->target;
  643.     scmd->cdb.g0_cdb.cmd = SC_WRITE;
  644.     scmd->cdb.g0_cdb.lun = scgp->lun;
  645.     g0_cdbaddr(&scmd->cdb.g0_cdb, addr);
  646.     scmd->cdb.g0_cdb.count = cnt;
  647.     
  648.     scgp->cmdname = "write_g0";
  649.  
  650.     return (scg_cmd(scgp));
  651. }
  652.  
  653. EXPORT int
  654. write_g1(scgp, bp, addr, cnt)
  655.     SCSI    *scgp;
  656.     caddr_t    bp;
  657.     long    addr;
  658.     int    cnt;
  659. {
  660.     register struct    scg_cmd    *scmd = scgp->scmd;
  661.  
  662.     if (scgp->cap->c_bsize <= 0)
  663.         raisecond("capacity_not_set", 0L);
  664.  
  665.     fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
  666.     scmd->addr = bp;
  667.     scmd->size = cnt*scgp->cap->c_bsize;
  668.     scmd->flags = SCG_DISRE_ENA;
  669.     scmd->cdb_len = SC_G1_CDBLEN;
  670.     scmd->sense_len = CCS_SENSE_LEN;
  671.     scmd->target = scgp->target;
  672.     scmd->cdb.g1_cdb.cmd = SC_EWRITE;
  673.     scmd->cdb.g1_cdb.lun = scgp->lun;
  674.     g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
  675.     g1_cdblen(&scmd->cdb.g1_cdb, cnt);
  676.     
  677.     scgp->cmdname = "write_g1";
  678.  
  679.     return (scg_cmd(scgp));
  680. }
  681.  
  682. #ifdef    used
  683. LOCAL void
  684. Xrequest_sense(scgp)
  685.     SCSI    *scgp;
  686. {
  687.     char    sense_buf[32];
  688.     struct    scg_cmd ocmd;
  689.     int    sense_count;
  690.     char    *cmdsave;
  691.     register struct    scg_cmd    *scmd = scgp->scmd;
  692.  
  693.     cmdsave = scgp->cmdname;
  694.  
  695.     movebytes(scmd, &ocmd, sizeof(*scmd));
  696.  
  697.     fillbytes((caddr_t)sense_buf, sizeof(sense_buf), '\0');
  698.  
  699.     fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
  700.     scmd->addr = (caddr_t)sense_buf;
  701.     scmd->size = sizeof(sense_buf);
  702.     scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
  703.     scmd->cdb_len = SC_G0_CDBLEN;
  704.     scmd->sense_len = CCS_SENSE_LEN;
  705.     scmd->target = scgp->target;
  706.     scmd->cdb.g1_cdb.cmd = 0x3;
  707.     scmd->cdb.g1_cdb.lun = scgp->lun;
  708.     scmd->cdb.g0_cdb.count = sizeof(sense_buf);
  709.     
  710.     scgp->cmdname = "request sense";
  711.  
  712.     scg_cmd(scgp);
  713.  
  714.     sense_count = sizeof(sense_buf) - scg_getresid(scgp);
  715.     movebytes(&ocmd, scmd, sizeof(*scmd));
  716.     scmd->sense_count = sense_count;
  717.     movebytes(sense_buf, (u_char *)&scmd->sense, scmd->sense_count);
  718.  
  719.     scgp->cmdname = cmdsave;
  720.     scg_printerr(scgp);
  721.     scg_printresult(scgp);    /* XXX restore key/code in future */
  722. }
  723. #endif
  724.  
  725. LOCAL int
  726. read_retry(scgp, bp, addr, cnt, rfunc, rp)
  727.     SCSI    *scgp;
  728.     caddr_t    bp;
  729.     long    addr;
  730.     long    cnt;
  731.     int    (*rfunc)__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
  732.     rparm_t    *rp;
  733. {
  734.     int    secsize = scgp->cap->c_bsize;
  735.     int    try = 0;
  736.     int    err;
  737.     char    dummybuf[8192];
  738.  
  739.     if (secsize > sizeof(dummybuf)) {
  740.         errmsgno(EX_BAD, "Cannot retry, sector size %d too big.\n", secsize);
  741.         return (-1);
  742.     }
  743.  
  744.     errmsgno(EX_BAD, "Retrying from sector %d.\n", addr);
  745.     while (cnt > 0) {
  746.         error(".");
  747.  
  748.         do {
  749.             if (try != 0) {
  750.                 if ((try % 8) == 0) {
  751.                     error("+");
  752.                     scgp->silent++;
  753.                     (*rfunc)(scgp, rp, dummybuf, scgp->cap->c_baddr, 1);
  754.                     scgp->silent--;
  755.                 } else if ((try % 4) == 0) {
  756.                     error("-");
  757.                     scgp->silent++;
  758.                     (*rfunc)(scgp, rp, dummybuf, 0, 1);
  759.                     scgp->silent--;
  760.                 } else {
  761.                     error("~");
  762.                     scgp->silent++;
  763.                     (*rfunc)(scgp, rp, dummybuf, choice(scgp->cap->c_baddr), 1);
  764.                     scgp->silent--;
  765.                 }
  766.             }
  767.  
  768.             fillbytes(bp, secsize, 0);
  769.  
  770.             scgp->silent++;
  771.             err = (*rfunc)(scgp, rp, bp, addr, 1);
  772.             scgp->silent--;
  773.  
  774.             if (err < 0) {
  775.                 err = scgp->scmd->ux_errno;
  776. /*                error("\n");*/
  777. /*                errmsgno(err, "Cannot read source disk\n");*/
  778.             } else {
  779.                 break;
  780.             }
  781.         } while (++try < retries);
  782.  
  783.         if (try >= retries) {
  784.             error("\n");
  785.             errmsgno(err, "Error on sector %d not corrected. Total of %d errors.\n", addr, ++rp->errors);
  786.             if (!noerror)
  787.                 return (-1);
  788.         } else {
  789.             if (try > 1) {
  790.                 error("\n");
  791.                 errmsgno(EX_BAD, "Error corrected after %d tries. Total of %d errors.\n", try, rp->errors);
  792.             }
  793.         }
  794.         try = 0;
  795.         cnt -= 1;
  796.         addr += 1;
  797.         bp += secsize;
  798.     }
  799.     return (0);
  800. }
  801.  
  802. LOCAL void
  803. read_generic(scgp, parmp, rfunc, rp, dfunc)
  804.     SCSI    *scgp;
  805.     parm_t    *parmp;
  806.     int    (*rfunc)__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
  807.     rparm_t    *rp;
  808.     int    (*dfunc)__PR((rparm_t *rp, caddr_t bp, long addr, int cnt));
  809. {
  810.     char    filename[512];
  811.     char    *defname = NULL;
  812.     FILE    *f;
  813.     long    addr;
  814.     long    num;
  815.     long    end = 0L;
  816.     long    start = 0L;
  817.     long    cnt;
  818.     int    msec;
  819.     int    err = 0;
  820.     BOOL    askrange = FALSE;
  821.     BOOL    isrange = FALSE;
  822.     int    secsize = rp->secsize;
  823.  
  824.     if (is_suid) {
  825.         if (scgp->inq->type != INQ_ROMD)
  826.             comerrno(EX_BAD, "Not root. Will only read from CD in suid mode\n");
  827.     }
  828.  
  829.     if (parmp == NULL || parmp->askrange)
  830.         askrange = TRUE;
  831.     if (parmp != NULL && !askrange && (parmp->start <= parmp->end))
  832.         isrange = TRUE;
  833.  
  834.     filename[0] ='\0';
  835.     if (read_capacity(scgp) >= 0)
  836.         end = scgp->cap->c_baddr + 1;
  837.  
  838.     if (end <= 0 || isrange || (askrange && scg_yes("Ignore disk size? ")))
  839.         end = 10000000;    /* Hack to read empty (e.g. blank=fast) disks */
  840.  
  841.     if (parmp) {
  842.         if (parmp->name)
  843.             defname = parmp->name;
  844.         if (defname != NULL) {
  845.             error("Copy from SCSI (%d,%d,%d) disk to file '%s'\n",
  846.                     scgp->scsibus, scgp->target, scgp->lun,
  847.                     defname);
  848.         }
  849.  
  850.         addr = start = parmp->start;
  851.         if (parmp->end != -1 && parmp->end < end)
  852.             end = parmp->end;
  853.         cnt = Sbufsize / secsize;
  854.     }
  855.  
  856.     if (defname == NULL) {
  857.         defname = "disk.out";
  858.         error("Copy from SCSI (%d,%d,%d) disk to file\n",
  859.                     scgp->scsibus, scgp->target, scgp->lun);
  860.         error("Enter filename [%s]: ", defname);flush();
  861.         (void)getline(filename, sizeof(filename));
  862.     }
  863.  
  864.     if (askrange) {
  865.         addr = start;
  866.         getlong("Enter starting sector for copy:", &addr, start, end-1);
  867. /*        getlong("Enter starting sector for copy:", &addr, -300, end-1);*/
  868.         start = addr;
  869.     }
  870.  
  871.     if (askrange) {
  872.         num = end - addr;
  873.         getlong("Enter number of sectors to copy:", &num, 1L, num);
  874.         end = addr + num;
  875.     }
  876.  
  877.     if (askrange) {
  878. /* XXX askcnt */
  879.         cnt = Sbufsize / secsize;
  880.         getlong("Enter number of sectors per copy:", &cnt, 1L, cnt);
  881.     }
  882.  
  883.     if (filename[0] == '\0')
  884.         strncpy(filename, defname, sizeof(filename));
  885.     filename[sizeof(filename)-1] = '\0';
  886.     if (streql(filename, "-")) {
  887.         f = stdout;
  888. #if    defined(__CYGWIN32__) || defined(__EMX__)
  889.         setmode(STDOUT_FILENO, O_BINARY);
  890. #endif
  891.     } else if ((f = fileopen(filename, "wcub")) == NULL)
  892.         comerr("Cannot open '%s'.\n", filename);
  893.  
  894.     error("end:  %8ld\n", end);
  895.     if (gettimeofday(&starttime, (struct timezone *)0) < 0)
  896.         comerr("Cannot get start time\n");
  897.  
  898.     for(;addr < end; addr += cnt) {
  899.  
  900.         if ((addr + cnt) > end)
  901.             cnt = end - addr;
  902.  
  903.         error("addr: %8d cnt: %d\r", addr, cnt);
  904.  
  905.         if ((*rfunc)(scgp, rp, Sbuf, addr, cnt) < 0) {
  906.             err = scgp->scmd->ux_errno;
  907.             error("\n");
  908.             errmsgno(err, "Cannot read source disk\n");
  909.  
  910.             if (read_retry(scgp, Sbuf, addr, cnt, rfunc, rp) < 0)
  911.                 goto out;
  912.         }
  913.         (*dfunc)(rp, Sbuf, addr, cnt);
  914.         if (filewrite(f, Sbuf, cnt * secsize) < 0) {
  915.             err = geterrno();
  916.             error("\n");
  917.             errmsgno(err, "Cannot write '%s'\n", filename);
  918.             break;
  919.         }
  920.     }
  921.     error("addr: %8d", addr);
  922. out:
  923.     error("\n");
  924.     msec = prstats();
  925. #ifdef    OOO
  926.     error("Read %.2f kB at %.1f kB/sec.\n",
  927.         (double)(addr - start)/(1024.0/scgp->cap->c_bsize),
  928.         (double)((addr - start)/(1024.0/scgp->cap->c_bsize)) / (0.001*msec));
  929. #else
  930.     error("Read %.2f kB at %.1f kB/sec.\n",
  931.         (double)(addr - start)/(1024.0/secsize),
  932.         (double)((addr - start)/(1024.0/secsize)) / (0.001*msec));
  933. #endif
  934. }
  935.  
  936. LOCAL void
  937. write_disk(scgp, parmp)
  938.     SCSI    *scgp;
  939.     parm_t    *parmp;
  940. {
  941.     char    filename[512];
  942.     char    *defname = "disk.out";
  943.     FILE    *f;
  944.     long    addr = 0L;
  945.     long    cnt;
  946.     long    amt;
  947.     long    end;
  948.     int    msec;
  949.     int    start;
  950.  
  951.     if (is_suid)
  952.         comerrno(EX_BAD, "Not root. Will not write in suid mode\n");
  953.  
  954.     filename[0] ='\0';
  955.     read_capacity(scgp);
  956.     end = scgp->cap->c_baddr + 1;
  957.  
  958.     if (end <= 0)
  959.         end = 10000000;    /* Hack to write empty disks */
  960.  
  961.     if (parmp) {
  962.         if (parmp->name)
  963.             defname = parmp->name;
  964.         error("Copy from file '%s' to SCSI (%d,%d,%d) disk\n",
  965.                     defname,
  966.                     scgp->scsibus, scgp->target, scgp->lun);
  967.  
  968.         addr = start = parmp->start;
  969.         if (parmp->end != -1 && parmp->end < end)
  970.             end = parmp->end;
  971.         cnt = Sbufsize / scgp->cap->c_bsize;
  972.     }
  973. else {
  974.  
  975.     error("Copy from file to SCSI (%d,%d,%d) disk\n",
  976.                     scgp->scsibus, scgp->target, scgp->lun);
  977.     error("Enter filename [%s]: ", defname);flush();
  978.     (void)getline(filename, sizeof(filename));
  979.     error("Notice: reading from file always starts at file offset 0.\n");
  980.  
  981.     getlong("Enter starting sector for copy:", &addr, 0L, end-1);
  982.     start = addr;
  983.     cnt = end - addr;
  984.     getlong("Enter number of sectors to copy:", &end, 1L, end);
  985.     end = addr + cnt;
  986.  
  987.     cnt = Sbufsize / scgp->cap->c_bsize;
  988.     getlong("Enter number of sectors per copy:", &cnt, 1L, cnt);
  989. /*    error("end:  %8ld\n", end);*/
  990. }
  991.  
  992.     if (filename[0] == '\0')
  993.         strncpy(filename, defname, sizeof(filename));
  994.     filename[sizeof(filename)-1] = '\0';
  995.     if (streql(filename, "-")) {
  996.         f = stdin;
  997. #if    defined(__CYGWIN32__) || defined(__EMX__)
  998.         setmode(STDIN_FILENO, O_BINARY);
  999. #endif
  1000.     } else if ((f = fileopen(filename, "rub")) == NULL)
  1001.         comerr("Cannot open '%s'.\n", filename);
  1002.  
  1003.     error("end:  %8ld\n", end);
  1004.     if (gettimeofday(&starttime, (struct timezone *)0) < 0)
  1005.         comerr("Cannot get start time\n");
  1006.  
  1007.     for(;addr < end; addr += cnt) {
  1008.  
  1009.         if ((addr + cnt) > end)
  1010.             cnt = end - addr;
  1011.  
  1012.         error("addr: %8d cnt: %d\r", addr, cnt);
  1013.  
  1014.         if ((amt = fileread(f, Sbuf, cnt * scgp->cap->c_bsize)) < 0)
  1015.             comerr("Cannot read '%s'\n", filename);
  1016.         if (amt == 0)
  1017.             break;
  1018.         if ((amt / scgp->cap->c_bsize) < cnt)
  1019.             cnt = amt / scgp->cap->c_bsize;
  1020.         if (write_scsi(scgp, Sbuf, addr, cnt) < 0)
  1021.             comerrno(scgp->scmd->ux_errno,
  1022.                     "Cannot write destination disk\n");
  1023.     }
  1024.     error("addr: %8d\n", addr);
  1025.     msec = prstats();
  1026.     error("Wrote %.2f kB at %.1f kB/sec.\n",
  1027.         (double)(addr - start)/(1024.0/scgp->cap->c_bsize),
  1028.         (double)((addr - start)/(1024.0/scgp->cap->c_bsize)) / (0.001*msec));
  1029. }
  1030.  
  1031. LOCAL int
  1032. choice(n)
  1033.     int    n;
  1034. {
  1035. #if    defined(HAVE_DRAND48)
  1036.     extern    double    drand48 __PR((void));
  1037.  
  1038.     return drand48() * n;
  1039. #else
  1040. #    if    defined(HAVE_RAND)
  1041.     extern    int    rand __PR((void));
  1042.  
  1043.     return rand() % n;
  1044. #    else
  1045.     return (0);
  1046. #    endif
  1047. #endif
  1048. }
  1049.  
  1050. LOCAL void
  1051. ra(scgp)
  1052.     SCSI    *scgp;
  1053. {
  1054. /*    char    filename[512];*/
  1055.     FILE    *f;
  1056. /*    long    addr = 0L;*/
  1057. /*    long    cnt;*/
  1058. /*    long    end;*/
  1059. /*    int    msec;*/
  1060. /*    int    start;*/
  1061. /*    int    err = 0;*/
  1062.  
  1063.     select_secsize(scgp, 2352);
  1064.     read_capacity(scgp);
  1065.     fillbytes(Sbuf, 50*2352, 0);
  1066.     if (read_g1(scgp, Sbuf, 0, 50) < 0)
  1067.         errmsg("read CD\n");
  1068.     f = fileopen("DDA", "wctb");
  1069. /*    filewrite(f, Sbuf, 50 * 2352 - scg_getresid(scgp));*/
  1070.     filewrite(f, Sbuf, 50 * 2352 );
  1071.     fclose(f);
  1072. }
  1073.  
  1074. #define    g5x_cdblen(cdb, len)    ((cdb)->count[0] = ((len) >> 16L)& 0xFF,\
  1075.                  (cdb)->count[1] = ((len) >> 8L) & 0xFF,\
  1076.                  (cdb)->count[2] = (len) & 0xFF)
  1077.  
  1078. EXPORT int
  1079. read_da(scgp, bp, addr, cnt, framesize, subcode)
  1080.     SCSI    *scgp;
  1081.     caddr_t    bp;
  1082.     long    addr;
  1083.     int    cnt;
  1084.     int    framesize;
  1085.     int    subcode;
  1086. {
  1087.     register struct    scg_cmd    *scmd = scgp->scmd;
  1088.  
  1089.     if (scgp->cap->c_bsize <= 0)
  1090.         raisecond("capacity_not_set", 0L);
  1091.  
  1092.     fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
  1093.     scmd->addr = bp;
  1094.     scmd->size = cnt*framesize;
  1095.     scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
  1096.     scmd->cdb_len = SC_G5_CDBLEN;
  1097.     scmd->sense_len = CCS_SENSE_LEN;
  1098.     scmd->target = scgp->target;
  1099.     scmd->cdb.g5_cdb.cmd = 0xd8;
  1100.     scmd->cdb.g5_cdb.lun = scgp->lun;
  1101.     g5_cdbaddr(&scmd->cdb.g1_cdb, addr);
  1102.     g5_cdblen(&scmd->cdb.g1_cdb, cnt);/* XXX subscript out of range ?? */
  1103.     g5x_cdblen(&scmd->cdb.g1_cdb, cnt);/* XXX subscript out of range ?? */
  1104.     scmd->cdb.g5_cdb.res10 = subcode;
  1105.     
  1106.     scgp->cmdname = "read_da";
  1107.  
  1108.     return (scg_cmd(scgp));
  1109. }
  1110.  
  1111. EXPORT int
  1112. read_cd(scgp, bp, addr, cnt, framesize, data, subch)
  1113.     SCSI    *scgp;
  1114.     caddr_t    bp;
  1115.     long    addr;
  1116.     int    cnt;
  1117.     int    framesize;
  1118.     int    data;
  1119.     int    subch;
  1120. {
  1121.     register struct    scg_cmd    *scmd = scgp->scmd;
  1122.  
  1123.     fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
  1124.     scmd->addr = bp;
  1125.     scmd->size = cnt*framesize;
  1126.     scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
  1127.     scmd->cdb_len = SC_G5_CDBLEN;
  1128.     scmd->sense_len = CCS_SENSE_LEN;
  1129.     scmd->target = scgp->target;
  1130.     scmd->cdb.g5_cdb.cmd = 0xBE;
  1131.     scmd->cdb.g5_cdb.lun = scgp->lun;
  1132.         scmd->cdb.g5_cdb.res = 0;    /* expected sector type field ALL */
  1133.     g5_cdbaddr(&scmd->cdb.g5_cdb, addr);
  1134.     g5x_cdblen(&scmd->cdb.g5_cdb, cnt);
  1135.  
  1136.     scmd->cdb.g5_cdb.count[3] = data & 0xFF;
  1137.         scmd->cdb.g5_cdb.res10 = subch & 0x07;
  1138.  
  1139.     scgp->cmdname = "read_cd";
  1140.  
  1141.     return (scg_cmd(scgp));
  1142. }
  1143.  
  1144.